﻿Imports System.Diagnostics
Imports System.IO
Imports System.Net.WebRequestMethods
Imports System.Text.RegularExpressions

''' <summary>
''' 管理多进程处理任务，控制并发数量并监控子进程状态。
''' 负责调度Excel文件拆分任务，通过事件通知进度和日志。
''' </summary>
Public Class ProcessManager

    '计划调用的子程序名称
    Public _ChildProcessName As String

    Private IsBusy As Boolean = False

    ''' <summary>
    ''' 最大并发进程数（默认值：4）。
    ''' 超出此数量时，新任务将等待已有进程完成。
    ''' </summary>
    Public Property MaxProcesses As Integer = 5

    ''' <summary>
    ''' 子进程输出文件的目录路径。
    ''' 子进程拆分后的Excel文件将保存到此目录。
    ''' </summary>
    Public Property OutputDirectory As String


    Public Property MbName As String


    ' 任务队列：存储待处理的Excel文件路径
    Private taskQueue As New Queue(Of String)
    ' 活动进程字典：Key=进程实例, Value=处理的文件路径
    Private activeProcesses As New Dictionary(Of Process, String)
    Private completedCount As Integer = 0  ' 已完成任务计数
    Private totalFiles As Integer = 0      ' 总任务数

    ''' <summary>
    ''' 当整体处理进度变化时触发（参数：进度百分比0-100）。
    ''' </summary>
    Public Event ProgressChanged(percent As Integer)

    ''' <summary>
    ''' 当需要记录处理日志时触发（参数：日志消息）。
    ''' </summary>
    Public Event LogMessage(message As String)

    ''' <summary>
    ''' 当所有任务完成时触发。
    ''' </summary>
    Public Event TaskCompleted()

    ''' <summary>
    ''' 添加待处理的Excel文件到任务队列。
    ''' </summary>
    ''' <param name="files">Excel文件路径集合</param>
    Public Sub AddTasks(files As IEnumerable(Of String))
        For Each file In files
            taskQueue.Enqueue(file)
        Next
        totalFiles = taskQueue.Count  ' 更新总任务数
        completedCount = 0
    End Sub

    ''' <summary>
    ''' 启动任务处理流程，根据最大并发数创建子进程。
    ''' </summary>
    Public Sub StartProcessing()
        If IsBusy Then
            RaiseEvent LogMessage("请等待之前的工作处理完成")
        Else
            IsBusy = True
        End If
        ' 循环启动进程直到达到最大并发数或队列为空
        While taskQueue.Count > 0 AndAlso activeProcesses.Count < MaxProcesses
            Dim file = taskQueue.Dequeue()
            StartChildProcess(file)
        End While
    End Sub

    ''' <summary>
    ''' 启动单个子进程处理Excel文件。
    ''' </summary>
    ''' <param name="filePath">Excel文件路径</param>
    Private Sub StartChildProcess(filePath As String)
        Dim name1 As String = Path.GetFileNameWithoutExtension(filePath)

        Dim proc As New Process()
        ' 配置子进程参数
        proc.StartInfo.FileName = _ChildProcessName  ' 子进程程序路径


        Select Case _ChildProcessName
            Case "fun1.exe"
                proc.StartInfo.Arguments = $"""{filePath}"" ""{OutputDirectory}"""
            Case "fun2.exe"
                proc.StartInfo.Arguments = $"""{filePath}"" ""{OutputDirectory}"" ""{MbName}"""
            Case "fun3_20251028.exe"
                proc.StartInfo.Arguments = $"""{filePath}"" ""{OutputDirectory}"" ""{MbName}"""
        End Select

        proc.StartInfo.UseShellExecute = False          ' 禁止使用Shell执行
        proc.StartInfo.CreateNoWindow = True         ' 不显示命令行窗口
        proc.StartInfo.RedirectStandardOutput = True  ' 捕获标准输出

        ' 启用事件通知（Exited事件必须设置此属性）
        proc.EnableRaisingEvents = True

        ' 绑定进程退出事件处理器
        AddHandler proc.Exited, Sub(sender, e)
                                    HandleProcessExit(DirectCast(sender, Process))
                                End Sub

        proc.Start()
        activeProcesses.Add(proc, filePath)  ' 跟踪进程与文件关系
        RaiseEvent LogMessage($"启动进程: {Path.GetFileName(filePath)}")
    End Sub

    ''' <summary>
    ''' 处理子进程退出事件：记录结果、更新进度并启动新任务。
    ''' </summary>
    ''' <param name="proc">退出的进程实例</param>
    Private Sub HandleProcessExit(proc As Process)
        ' 获取进程对应的原始文件并移除跟踪
        Dim originalFile = activeProcesses(proc)
        activeProcesses.Remove(proc)

        ' 读取子进程输出（子进程成功时返回拆分后的文件名列表）
        Dim output = proc.StandardOutput.ReadToEnd()

        If proc.ExitCode = 0 Then
            ' 成功：解析拆分结果（格式：文件名1|文件名2|...）

            RaiseEvent LogMessage($"生成文件: {output.Trim()}")

        Else
            ' 失败：记录错误信息（子进程输出中已包含错误详情）
            RaiseEvent LogMessage($"处理失败: {Path.GetFileName(originalFile)} - {output}")
        End If

        ' 更新进度
        completedCount += 1
        Dim progress = CInt((completedCount * 100 / totalFiles))
        RaiseEvent ProgressChanged(progress)

        ' 启动新任务或结束
        If taskQueue.Count > 0 Then
            ' 从队列取出新文件并启动进程（保持最大并发）
            StartChildProcess(taskQueue.Dequeue())
        ElseIf activeProcesses.Count = 0 Then
            IsBusy = False
            ' 所有任务完成且无活动进程
            RaiseEvent TaskCompleted()
        End If
    End Sub
End Class